package io.kumao.gateway.route;

import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Lists;
import io.kumao.gateway.model.RouteConfig;
import io.kumao.gateway.service.OjmService;
import io.kumao.gateway.service.RouteConfigService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.List;

/**
 * DynamicRouteDefinitionRepository
 *
 * @author 崔作利
 */
@Slf4j
@Component
public class DynamicRouteDefinitionRepository implements RouteDefinitionRepository {

    @Autowired
    private OjmService ojm;

    @Resource
    private RouteConfigService routeConfigService;

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return route.flatMap(r -> {
            String routeID = r.getId();
            String predicates = ojm.json(r.getPredicates());
            String filters = ojm.json(r.getFilters());
            String uri = r.getUri().toString();
            int order = r.getOrder();
            Integer enableStatus = 1;
            String creator = "system";

            RouteConfig routeConfig = new RouteConfig();
            routeConfig.setRouteID(routeID);
            routeConfig.setPredicates(predicates);
            routeConfig.setFilters(filters);
            routeConfig.setUri(uri);
            routeConfig.setOrderNO(order);
            routeConfig.setEnableStatus(enableStatus);
            routeConfig.setCreator(creator);

            routeConfigService.createRouteConfig(routeConfig);
            return Mono.empty();
        });
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return routeId.flatMap(id -> {
            boolean success = routeConfigService.deleteRouteConfig(id);
            return success ? Mono.empty() : Mono.defer(() -> Mono.error(new NotFoundException("RouteDefinition not found: " + id)));
        });
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        List<RouteConfig> routeConfigs = routeConfigService.getRouteConfigList();
        List<RouteDefinition> definitions = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(routeConfigs)) {
            for (RouteConfig routeConfig : routeConfigs) {
                String id = routeConfig.getRouteID();
                // 断言
                String predicateConfig = routeConfig.getPredicates();
                List<PredicateDefinition> predicates = ojm.object(predicateConfig, new TypeReference<List<PredicateDefinition>>() {
                });
                // 过滤器
                String filterConfig = routeConfig.getFilters();
                List<FilterDefinition> filters = ojm.object(filterConfig, new TypeReference<List<FilterDefinition>>() {
                });
                // 回调地址
                URI uri = URI.create(routeConfig.getUri());
                int order = routeConfig.getOrderNO();

                RouteDefinition definition = new RouteDefinition();
                definition.setId(id);
                definition.setPredicates(predicates);
                definition.setFilters(filters);
                definition.setUri(uri);
                definition.setOrder(order);
                definitions.add(definition);
            }
        }
        return Flux.fromIterable(definitions);
    }
}
